home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 June / MacFormat 25.iso / Shareware City / Developers / OutOfPhase1.1 Source / OutOfPhase Folder / DiskFileOutput.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-05  |  27.7 KB  |  911 lines  |  [TEXT/KAHL]

  1. /* DiskFileOutput.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    Out Of Phase:  Digital Music Synthesis on General Purpose Computers    */
  5. /*    Copyright (C) 1994  Thomas R. Lawrence                                 */
  6. /*                                                                           */
  7. /*    This program is free software; you can redistribute it and/or modify   */
  8. /*    it under the terms of the GNU General Public License as published by   */
  9. /*    the Free Software Foundation; either version 2 of the License, or      */
  10. /*    (at your option) any later version.                                    */
  11. /*                                                                           */
  12. /*    This program is distributed in the hope that it will be useful,        */
  13. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  14. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
  15. /*    GNU General Public License for more details.                           */
  16. /*                                                                           */
  17. /*    You should have received a copy of the GNU General Public License      */
  18. /*    along with this program; if not, write to the Free Software            */
  19. /*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
  20. /*                                                                           */
  21. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  22. /*                                                                           */
  23. /*****************************************************************************/
  24.  
  25. #include "MiscInfo.h"
  26. #include "Audit.h"
  27. #include "Debug.h"
  28. #include "Definitions.h"
  29.  
  30. #include "DiskFileOutput.h"
  31. #include "Files.h"
  32. #include "Memory.h"
  33. #include "Alert.h"
  34. #include "ExecuteSynthesis.h"
  35. #include "ClipWarnDialog.h"
  36. #include "SynthProgressWindow.h"
  37. #include "BufferedFileOutput.h"
  38. #include "ErrorDaemon.h"
  39.  
  40.  
  41. #define CANCELCHECKTIMER (50)
  42.  
  43.  
  44. typedef struct
  45.     {
  46.         MyBoolean                            UseStereo;
  47.         long                                    SamplingRate;
  48.         OutputNumBitsType            NumBitsOut;
  49.         FileType*                            OutputFile;
  50.  
  51.         void*                                    Buffer;
  52.         long                                    BufferSizeInBytes;
  53.         char*                                    DataOutThing;
  54.         long                                    DataOutInBytes;
  55.  
  56.         long                                    TotalSampleCount;
  57.         long                                    ClippedSampleCount;
  58.         largefixedsigned            MaxClipExtent;
  59.  
  60.         long                                    CancelCheck;
  61.  
  62.         SynthWinRec*                    Window;
  63.     } StateRecord;
  64.  
  65.  
  66. /* AIFF/AIFF-C File Format: */
  67. /*     "FORM" */
  68. /*     4-byte big endian form chunk length descriptor (minus 8 for "FORM" & this) */
  69. /*     4-byte type */
  70. /*        "AIFF" = AIFF format file */
  71. /*        "AIFC" = AIFF-C format file */
  72. /* in any order, these chunks can occur: */
  73. /*   Version Chunk (this only occurs in AIFF-C files) */
  74. /*     "FVER" */
  75. /*     4-byte big endian length, which should always be the value 4 (four) */
  76. /*     4-byte date code.  this is probably 0xA2805140 (stored big endian), but it */
  77. /*          probably doesn't matter. */
  78. /*   Common Chunk for AIFF files */
  79. /*     "COMM" */
  80. /*     4-byte big endian length. */
  81. /*        always 18 for AIFF files */
  82. /*     2-byte big endian number of channels */
  83. /*     4-byte big endian number of sample frames */
  84. /*     2-byte big endian number of bits per sample */
  85. /*        a value in the domain 1..32 */
  86. /*     10-byte extended precision number of frames per second */
  87. /*   Common Chunk for AIFF-C files */
  88. /*     "COMM" */
  89. /*     4-byte big endian length. */
  90. /*        22 + compression method string length for AIFF-C files */
  91. /*     2-byte big endian number of channels */
  92. /*     4-byte big endian number of sample frames */
  93. /*     2-byte big endian number of bits per sample */
  94. /*        a value in the domain 1..32 */
  95. /*     10-byte extended precision number of frames per second */
  96. /*     4-byte character code ID for the compression method */
  97. /*        "NONE" means there is no compression method used */
  98. /*     some characters in a string identifying the compression method */
  99. /*        this must be padded to an even number of bytes, but the pad is */
  100. /*        NOT included in the length descriptor for the chunk. */
  101. /*        for uncompressed data, the string should be */
  102. /*        "\x0enot compressed\x00", including the null, for 16 bytes. */
  103. /*        the total chunk length is thus 38 bytes. */
  104. /*   Sound Data Chunk */
  105. /*     "SSND" */
  106. /*     4-byte big endian number of bytes in sample data array */
  107. /*     4-byte big endian offset to the first byte of sample data in the array */
  108. /*     4-byte big endian number of bytes to which the sound data is aligned. */
  109. /*     any length vector of raw sound data. */
  110. /*        this must be padded to an even number of bytes, but the pad is */
  111. /*        NOT included in the length descriptor for the chunk. */
  112. /*        Samples are stored in an integral number of bytes, the smallest that */
  113. /*        is required for the specified number of bits.  If this is not an even */
  114. /*        multiple of 8, then the data is shifted left and the low bits are zeroed */
  115. /*        Multichannel sound is interleaved with the left channel first. */
  116. static MyBoolean            SetUpAIFFHeader(FileType* OutputFile, StateRecord* Info)
  117.     {
  118.         BufferedOutputRec*    Output;
  119.         unsigned long                Mantissa;
  120.         unsigned long                Exponent;
  121.         char                                StupidExtendedThing[10];
  122.  
  123.         Output = NewBufferedOutput(OutputFile);
  124.         if (Output == NIL)
  125.             {
  126.              FailurePoint1:
  127.                 return False;
  128.             }
  129.  
  130.         /* 0..3 */
  131.         /*     "FORM" */
  132.         if (!WriteBufferedOutput(Output,4,"FORM"))
  133.             {
  134.              FailurePoint2:
  135.                 EndBufferedOutput(Output);
  136.                 goto FailurePoint1;
  137.             }
  138.  
  139.         /* 4..7 */
  140.         /*     4-byte big endian form chunk length descriptor (minus 8 for "FORM" & this) */
  141.         if (!WriteBufferedUnsignedLongBigEndian(Output,0)) /* RESOLVED LATER */
  142.             {
  143.                 goto FailurePoint2;
  144.             }
  145.  
  146.         /* 8..11 */
  147.         /*     4-byte type */
  148.         /*        "AIFC" = AIFF-C format file */
  149.         if (!WriteBufferedOutput(Output,4,"AIFC"))
  150.             {
  151.                 goto FailurePoint2;
  152.             }
  153.  
  154.         /* 12..15 */
  155.         /*     "FVER" */
  156.         if (!WriteBufferedOutput(Output,4,"FVER"))
  157.             {
  158.                 goto FailurePoint2;
  159.             }
  160.  
  161.         /* 16..19 */
  162.         /*     4-byte big endian length, which should always be the value 4 (four) */
  163.         if (!WriteBufferedUnsignedLongBigEndian(Output,4))
  164.             {
  165.                 goto FailurePoint2;
  166.             }
  167.  
  168.         /* 20..23 */
  169.         /*     4-byte date code.  this is probably 0xA2805140 (stored big endian), but it */
  170.         /*          probably doesn't matter. */
  171.         if (!WriteBufferedUnsignedLongBigEndian(Output,0xA2805140))
  172.             {
  173.                 goto FailurePoint2;
  174.             }
  175.  
  176.         /* 24..27 */
  177.         /*     "COMM" */
  178.         if (!WriteBufferedOutput(Output,4,"COMM"))
  179.             {
  180.                 goto FailurePoint2;
  181.             }
  182.  
  183.         /* 28..31 */
  184.         /*     4-byte big endian length. */
  185.         /*        22 + compression method string length for AIFF-C files */
  186.         if (!WriteBufferedUnsignedLongBigEndian(Output,38))
  187.             {
  188.                 goto FailurePoint2;
  189.             }
  190.  
  191.         /* 32..33 */
  192.         /*     2-byte big endian number of channels */
  193.         if (Info->UseStereo)
  194.             {
  195.                 if (!WriteBufferedUnsignedShortBigEndian(Output,2))
  196.                     {
  197.                         goto FailurePoint2;
  198.                     }
  199.             }
  200.          else
  201.             {
  202.                 if (!WriteBufferedUnsignedShortBigEndian(Output,1))
  203.                     {
  204.                         goto FailurePoint2;
  205.                     }
  206.             }
  207.  
  208.         /* 34..37 */
  209.         /*     4-byte big endian number of sample frames */
  210.         if (!WriteBufferedUnsignedLongBigEndian(Output,0)) /* RESOLVED LATER */
  211.             {
  212.                 goto FailurePoint2;
  213.             }
  214.  
  215.         /* 38..39 */
  216.         /*     2-byte big endian number of bits per sample */
  217.         /*        a value in the domain 1..32 */
  218.         switch (Info->NumBitsOut)
  219.             {
  220.                 default:
  221.                     EXECUTE(PRERR(ForceAbort,"SetUpAIFFHeader:  bad number of bits"));
  222.                     break;
  223.                 case eOutput8Bits:
  224.                     if (!WriteBufferedUnsignedShortBigEndian(Output,8))
  225.                         {
  226.                             goto FailurePoint2;
  227.                         }
  228.                     break;
  229.                 case eOutput16Bits:
  230.                     if (!WriteBufferedUnsignedShortBigEndian(Output,16))
  231.                         {
  232.                             goto FailurePoint2;
  233.                         }
  234.                     break;
  235.                 case eOutput24Bits:
  236.                     if (!WriteBufferedUnsignedShortBigEndian(Output,24))
  237.                         {
  238.                             goto FailurePoint2;
  239.                         }
  240.                     break;
  241.                 case eOutput32Bits:
  242.                     if (!WriteBufferedUnsignedShortBigEndian(Output,32))
  243.                         {
  244.                             goto FailurePoint2;
  245.                         }
  246.                     break;
  247.             }
  248.  
  249.         /* 40..49 */
  250.         /*     10-byte extended precision number of frames per second */
  251.         /* extended 22050 = 400D AC44000000000000 */
  252.         /* extended 22051 = 400D AC46000000000000 */
  253.         /* extended 44100 = 400E AC44000000000000 */
  254.         /* extended 44101 = 400E AC45000000000000 */
  255.         Exponent = 0x401e;
  256.         Mantissa = Info->SamplingRate;
  257.         while ((Mantissa & 0x80000000) == 0)
  258.             {
  259.                 Mantissa = Mantissa << 1;
  260.                 Exponent -= 1;
  261.             }
  262.         StupidExtendedThing[0] = (Exponent >> 8) & 0xff;
  263.         StupidExtendedThing[1] = Exponent & 0xff;
  264.         StupidExtendedThing[2] = (Mantissa >> 24) & 0xff;
  265.         StupidExtendedThing[3] = (Mantissa >> 16) & 0xff;
  266.         StupidExtendedThing[4] = (Mantissa >> 8) & 0xff;
  267.         StupidExtendedThing[5] = Mantissa & 0xff;
  268.         StupidExtendedThing[6] = 0;
  269.         StupidExtendedThing[7] = 0;
  270.         StupidExtendedThing[8] = 0;
  271.         StupidExtendedThing[9] = 0;
  272.         if (!WriteBufferedOutput(Output,10,StupidExtendedThing))
  273.             {
  274.                 goto FailurePoint2;
  275.             }
  276.  
  277.         /* 50..53 */
  278.         /*     4-byte character code ID for the compression method */
  279.         /*        "NONE" means there is no compression method used */
  280.         if (!WriteBufferedOutput(Output,4,"NONE"))
  281.             {
  282.                 goto FailurePoint2;
  283.             }
  284.  
  285.         /* 54..69 */
  286.         /*     some characters in a string identifying the compression method */
  287.         /*        this must be padded to an even number of bytes, but the pad is */
  288.         /*        NOT included in the length descriptor for the chunk. */
  289.         /*        for uncompressed data, the string should be */
  290.         /*        "\x0enot compressed\x00", including the null, for 16 bytes. */
  291.         /*        the total chunk length is thus 38 bytes. */
  292.         if (!WriteBufferedOutput(Output,16,"\x0enot compressed\x00"))
  293.             {
  294.                 goto FailurePoint2;
  295.             }
  296.  
  297.         /* 70..73 */
  298.         /*     "SSND" */
  299.         if (!WriteBufferedOutput(Output,4,"SSND"))
  300.             {
  301.                 goto FailurePoint2;
  302.             }
  303.  
  304.         /* 74..77 */
  305.         /*     4-byte big endian number of bytes in sample data array */
  306.         if (!WriteBufferedUnsignedLongBigEndian(Output,0)) /* RESOLVED LATER */
  307.             {
  308.                 goto FailurePoint2;
  309.             }
  310.  
  311.         /* 78..81 */
  312.         /*     4-byte big endian offset to the first byte of sample data in the array */
  313.         if (!WriteBufferedUnsignedLongBigEndian(Output,0))
  314.             {
  315.                 goto FailurePoint2;
  316.             }
  317.  
  318.         /* 82..85 */
  319.         /*     4-byte big endian number of bytes to which the sound data is aligned. */
  320.         if (!WriteBufferedUnsignedLongBigEndian(Output,0))
  321.             {
  322.                 goto FailurePoint2;
  323.             }
  324.  
  325.         /*     any length vector of raw sound data. */
  326.         /*        this must be padded to an even number of bytes, but the pad is */
  327.         /*        NOT included in the length descriptor for the chunk. */
  328.         /*        Samples are stored in an integral number of bytes, the smallest that */
  329.         /*        is required for the specified number of bits.  If this is not an even */
  330.         /*        multiple of 8, then the data is shifted left and the low bits are zeroed */
  331.         /*        Multichannel sound is interleaved with the left channel first. */
  332.  
  333.         if (!EndBufferedOutput(Output))
  334.             {
  335.                 return False;
  336.             }
  337.  
  338.         return True;
  339.     }
  340.  
  341.  
  342. /* update various size fields in the file */
  343. static MyBoolean            ResolveAIFFHeader(FileType* OutputFile, StateRecord* Info)
  344.     {
  345.         long                                TotalBytesOfSamples;
  346.         MyBoolean                        FileSuccess;
  347.         char                                Buffer[4];
  348.  
  349.         TotalBytesOfSamples = Info->TotalSampleCount;
  350.         if (Info->UseStereo)
  351.             {
  352.                 TotalBytesOfSamples *= 2;
  353.             }
  354.         switch (Info->NumBitsOut)
  355.             {
  356.                 default:
  357.                     EXECUTE(PRERR(ForceAbort,"ResolveAIFFHeader:  bad number of bits"));
  358.                     break;
  359.                 case eOutput8Bits:
  360.                     break;
  361.                 case eOutput16Bits:
  362.                     TotalBytesOfSamples *= 2;
  363.                     break;
  364.                 case eOutput24Bits:
  365.                     TotalBytesOfSamples *= 3;
  366.                     break;
  367.                 case eOutput32Bits:
  368.                     TotalBytesOfSamples *= 4;
  369.                     break;
  370.             }
  371.  
  372.         FileSuccess = True;
  373.  
  374.         /* make sure file is an even number of bytes */
  375.         if ((GetFilePosition(OutputFile) & 1) != 0)
  376.             {
  377.                 char                        Stupid[1] = {0};
  378.  
  379.                 if (0 != WriteToFile(OutputFile,Stupid,1))
  380.                     {
  381.                         FileSuccess = False;
  382.                     }
  383.             }
  384.  
  385.         /* chop off any crud from the end */
  386.         FileSuccess = SetFileLength(OutputFile,GetFilePosition(OutputFile)) && FileSuccess;
  387.  
  388.         /* 4..7 */
  389.         /*     4-byte big endian form chunk length descriptor (minus 8 for "FORM" & this) */
  390.         if (SetFilePosition(OutputFile,4))
  391.             {
  392.                 Buffer[0] = ((TotalBytesOfSamples + 78) >> 24) & 0xff;
  393.                 Buffer[1] = ((TotalBytesOfSamples + 78) >> 16) & 0xff;
  394.                 Buffer[2] = ((TotalBytesOfSamples + 78) >> 8) & 0xff;
  395.                 Buffer[3] = (TotalBytesOfSamples + 78) & 0xff;
  396.                 if (0 != WriteToFile(OutputFile,Buffer,4))
  397.                     {
  398.                         FileSuccess = False;
  399.                     }
  400.             }
  401.          else
  402.             {
  403.                 FileSuccess = False;
  404.             }
  405.  
  406.         /* 34..37 */
  407.         /*     4-byte big endian number of sample frames */
  408.         if (SetFilePosition(OutputFile,34))
  409.             {
  410.                 Buffer[0] = (Info->TotalSampleCount >> 24) & 0xff;
  411.                 Buffer[1] = (Info->TotalSampleCount >> 16) & 0xff;
  412.                 Buffer[2] = (Info->TotalSampleCount >> 8) & 0xff;
  413.                 Buffer[3] = Info->TotalSampleCount & 0xff;
  414.                 if (0 != WriteToFile(OutputFile,Buffer,4))
  415.                     {
  416.                         FileSuccess = False;
  417.                     }
  418.             }
  419.          else
  420.             {
  421.                 FileSuccess = False;
  422.             }
  423.  
  424.         /* 74..77 */
  425.         /*     4-byte big endian number of bytes in sample data array */
  426.         if (SetFilePosition(OutputFile,74))
  427.             {
  428.                 Buffer[0] = ((TotalBytesOfSamples + 8) >> 24) & 0xff;
  429.                 Buffer[1] = ((TotalBytesOfSamples + 8) >> 16) & 0xff;
  430.                 Buffer[2] = ((TotalBytesOfSamples + 8) >> 8) & 0xff;
  431.                 Buffer[3] = (TotalBytesOfSamples + 8) & 0xff;
  432.                 if (0 != WriteToFile(OutputFile,Buffer,4))
  433.                     {
  434.                         FileSuccess = False;
  435.                     }
  436.             }
  437.          else
  438.             {
  439.                 FileSuccess = False;
  440.             }
  441.  
  442.         return FileSuccess;
  443.     }
  444.  
  445.  
  446. static MyBoolean            CallbackRoutine(StateRecord* Info, largefixedsigned* DataBlock,
  447.                                                 long NumFrames, MyBoolean* AbortPlaybackFlagOut)
  448.     {
  449.         long                                Limit;
  450.         void*                                Buffer;
  451.         long                                BufferSizeInBytes;
  452.         char*                                DataOutThing;
  453.         long                                DataOutInBytes;
  454.         long                                Scan;
  455.         largefixedsigned        TempValue;
  456.         long                                UnwritableBytes;
  457.  
  458.         Info->CancelCheck -= 1;
  459.         if (Info->CancelCheck < 0)
  460.             {
  461.                 Info->CancelCheck = CANCELCHECKTIMER;
  462.                 if (RelinquishCPUJudiciouslyCheckCancel())
  463.                     {
  464.                         switch (AskYesNoCancel("Are you sure you want to abort synthesis?",NIL,
  465.                             "Abort","Resume",NIL))
  466.                             {
  467.                                 default:
  468.                                     EXECUTE(PRERR(ForceAbort,"DiskFileOutput:CallbackRoutine:  bad value "
  469.                                         "from AskYesNoCancel"));
  470.                                     break;
  471.                                 case eYes:
  472.                                     *AbortPlaybackFlagOut = True;
  473.                                     return True;
  474.                                 case eNo:
  475.                                     break;
  476.                             }
  477.                         /* at first glance, we might need to somehow reset the RelinquishCPU */
  478.                         /* sticky cancel flag, but AskYesNoCancel calls the event loop, so */
  479.                         /* it gets automatically reset. */
  480.                     }
  481.             }
  482.  
  483.         /* calculate required buffer size */
  484.         Limit = NumFrames;
  485.         BufferSizeInBytes = NumFrames;
  486.         DataOutInBytes = NumFrames;
  487.         if (Info->UseStereo)
  488.             {
  489.                 Limit *= 2; /* twice as many frames for stereo */
  490.                 BufferSizeInBytes *= 2;
  491.                 DataOutInBytes *= 2;
  492.             }
  493.         switch (Info->NumBitsOut)
  494.             {
  495.                 default:
  496.                     EXECUTE(PRERR(ForceAbort,"CallbackRoutine:  bad number of bits"));
  497.                     break;
  498.                 case eOutput8Bits:
  499.                     break;
  500.                 case eOutput16Bits:
  501.                     BufferSizeInBytes *= sizeof(short);
  502.                     DataOutInBytes *= 2;
  503.                     break;
  504.                 case eOutput24Bits:
  505.                     BufferSizeInBytes *= sizeof(largefixedsigned);
  506.                     DataOutInBytes *= 3;
  507.                     break;
  508.                 case eOutput32Bits:
  509.                     BufferSizeInBytes *= sizeof(largefixedsigned);
  510.                     DataOutInBytes *= 4;
  511.                     break;
  512.             }
  513.         if (Info->BufferSizeInBytes < BufferSizeInBytes)
  514.             {
  515.                 Buffer = ResizePtr((char*)Info->Buffer,BufferSizeInBytes);
  516.                 if (Buffer == NIL)
  517.                     {
  518.                         AlertHalt("There is not enough memory available to continue synthesis.",NIL);
  519.                         return False;
  520.                     }
  521.                 Info->Buffer = Buffer;
  522.                 Info->BufferSizeInBytes = BufferSizeInBytes;
  523.             }
  524.          else
  525.             {
  526.                 Buffer = Info->Buffer;
  527.             }
  528.         if (Info->DataOutInBytes < DataOutInBytes)
  529.             {
  530.                 DataOutThing = ResizePtr(Info->DataOutThing,DataOutInBytes);
  531.                 if (DataOutThing == NIL)
  532.                     {
  533.                         AlertHalt("There is not enough memory available to continue synthesis.",NIL);
  534.                         return False;
  535.                     }
  536.                 Info->DataOutThing = DataOutThing;
  537.                 Info->DataOutInBytes = DataOutInBytes;
  538.             }
  539.          else
  540.             {
  541.                 DataOutThing = Info->DataOutThing;
  542.             }
  543.  
  544.         /* generate the data into the buffer */
  545.         switch (Info->NumBitsOut)
  546.             {
  547.                 default:
  548.                     EXECUTE(PRERR(ForceAbort,"SynthToAIFFFile:  bad number of bits"));
  549.                     break;
  550.                 case eOutput8Bits:
  551.                     for (Scan = 0; Scan < Limit; Scan += 1)
  552.                         {
  553.                             PRNGCHK(DataBlock,&(DataBlock[Scan]),sizeof(DataBlock[Scan]));
  554.                             TempValue = DataBlock[Scan] + double2largefixed((double)1 / 65536);
  555.                             /* 1 / 65536 is .5 for 16 bit signal */
  556.                             if (TempValue > int2largefixed(1) - 1)
  557.                                 {
  558.                                     Info->ClippedSampleCount += 1;
  559.                                     if (TempValue > Info->MaxClipExtent)
  560.                                         {
  561.                                             Info->MaxClipExtent = TempValue;
  562.                                         }
  563.                                     TempValue = int2largefixed(1) - 1;
  564.                                 }
  565.                             else if (TempValue < - (int2largefixed(1) - 1))
  566.                                 {
  567.                                     Info->ClippedSampleCount += 1;
  568.                                     if (- TempValue > Info->MaxClipExtent)
  569.                                         {
  570.                                             Info->MaxClipExtent = - TempValue;
  571.                                         }
  572.                                     TempValue = - (int2largefixed(1) - 1);
  573.                                 }
  574.                             PRNGCHK(Buffer,&(((signed char*)Buffer)[Scan]),
  575.                                 sizeof(((signed char*)Buffer)[Scan]));
  576.                             ((signed char*)Buffer)[Scan] = TempValue >> (largefixed_precision - 8 + 1);
  577.                         }
  578.                     break;
  579.                 case eOutput16Bits:
  580.                     for (Scan = 0; Scan < Limit; Scan += 1)
  581.                         {
  582.                             PRNGCHK(DataBlock,&(DataBlock[Scan]),sizeof(DataBlock[Scan]));
  583.                             TempValue = DataBlock[Scan] + double2largefixed((double)1 / 65536);
  584.                             if (TempValue > int2largefixed(1) - 1)
  585.                                 {
  586.                                     Info->ClippedSampleCount += 1;
  587.                                     if (TempValue > Info->MaxClipExtent)
  588.                                         {
  589.                                             Info->MaxClipExtent = TempValue;
  590.                                         }
  591.                                     TempValue = int2largefixed(1) - 1;
  592.                                 }
  593.                             else if (TempValue < - (int2largefixed(1) - 1))
  594.                                 {
  595.                                     Info->ClippedSampleCount += 1;
  596.                                     if (- TempValue > Info->MaxClipExtent)
  597.                                         {
  598.                                             Info->MaxClipExtent = - TempValue;
  599.                                         }
  600.                                     TempValue = - (int2largefixed(1) - 1);
  601.                                 }
  602.                             PRNGCHK(Buffer,&(((signed short*)Buffer)[Scan]),
  603.                                 sizeof(((signed short*)Buffer)[Scan]));
  604.                             ((signed short*)Buffer)[Scan] = TempValue >> (largefixed_precision - 16 + 1);
  605.                         }
  606.                     break;
  607.                 case eOutput24Bits:
  608.                     for (Scan = 0; Scan < Limit; Scan += 1)
  609.                         {
  610.                             PRNGCHK(DataBlock,&(DataBlock[Scan]),sizeof(DataBlock[Scan]));
  611.                             TempValue = DataBlock[Scan];
  612.                             if (TempValue > int2largefixed(1) - 1)
  613.                                 {
  614.                                     Info->ClippedSampleCount += 1;
  615.                                     if (TempValue > Info->MaxClipExtent)
  616.                                         {
  617.                                             Info->MaxClipExtent = TempValue;
  618.                                         }
  619.                                     TempValue = int2largefixed(1) - 1;
  620.                                 }
  621.                             else if (TempValue < - (int2largefixed(1) - 1))
  622.                                 {
  623.                                     Info->ClippedSampleCount += 1;
  624.                                     if (- TempValue > Info->MaxClipExtent)
  625.                                         {
  626.                                             Info->MaxClipExtent = - TempValue;
  627.                                         }
  628.                                     TempValue = - (int2largefixed(1) - 1);
  629.                                 }
  630.                             PRNGCHK(Buffer,&(((signed short*)Buffer)[Scan]),
  631.                                 sizeof(((signed short*)Buffer)[Scan]));
  632.                             ((largefixedsigned*)Buffer)[Scan] = TempValue >> (largefixed_precision - 24 + 1);
  633.                         }
  634.                     break;
  635.                 case eOutput32Bits:
  636.                     /* 32-bits doesn't clip. */
  637.                     for (Scan = 0; Scan < Limit; Scan += 1)
  638.                         {
  639.                             PRNGCHK(DataBlock,&(DataBlock[Scan]),sizeof(DataBlock[Scan]));
  640.                             TempValue = DataBlock[Scan];
  641.                             PRNGCHK(Buffer,&(((signed short*)Buffer)[Scan]),
  642.                                 sizeof(((signed short*)Buffer)[Scan]));
  643.                             ((largefixedsigned*)Buffer)[Scan] = TempValue;
  644.                         }
  645.                     break;
  646.             }
  647.  
  648.         /* reorder the data to be big-endian */
  649.         switch (Info->NumBitsOut)
  650.             {
  651.                 default:
  652.                     EXECUTE(PRERR(ForceAbort,"SynthToAIFFFile:  bad number of bits"));
  653.                     break;
  654.                 case eOutput8Bits:
  655.                     for (Scan = 0; Scan < Limit; Scan += 1)
  656.                         {
  657.                             signed short                TempVal;
  658.  
  659.                             PRNGCHK(Buffer,&(((signed char*)Buffer)[Scan]),
  660.                                 sizeof(((signed char*)Buffer)[Scan]));
  661.                             TempVal = ((signed char*)Buffer)[Scan];
  662.                             PRNGCHK(DataOutThing,&(DataOutThing[Scan]),sizeof(DataOutThing[Scan]));
  663.                             DataOutThing[Scan] = TempVal;
  664.                         }
  665.                     break;
  666.                 case eOutput16Bits:
  667.                     for (Scan = 0; Scan < Limit; Scan += 1)
  668.                         {
  669.                             signed short                TempVal;
  670.  
  671.                             PRNGCHK(Buffer,&(((signed short*)Buffer)[Scan]),
  672.                                 sizeof(((signed short*)Buffer)[Scan]));
  673.                             TempVal = ((signed short*)Buffer)[Scan];
  674.                             PRNGCHK(DataOutThing,&(DataOutThing[2 * Scan + 0]),
  675.                                 sizeof(DataOutThing[2 * Scan + 0]) * 2);
  676.                             DataOutThing[2 * Scan + 1] = TempVal & 0xff;
  677.                             DataOutThing[2 * Scan + 0] = (TempVal >> 8) & 0xff;
  678.                         }
  679.                     break;
  680.                 case eOutput24Bits:
  681.                     for (Scan = 0; Scan < Limit; Scan += 1)
  682.                         {
  683.                             largefixedsigned        TempVal;
  684.  
  685.                             PRNGCHK(Buffer,&(((largefixedsigned*)Buffer)[Scan]),
  686.                                 sizeof(((largefixedsigned*)Buffer)[Scan]));
  687.                             TempVal = ((largefixedsigned*)Buffer)[Scan];
  688.                             PRNGCHK(DataOutThing,&(DataOutThing[3 * Scan + 0]),
  689.                                 sizeof(DataOutThing[3 * Scan + 0]) * 3);
  690.                             DataOutThing[3 * Scan + 2] = TempVal & 0xff;
  691.                             DataOutThing[3 * Scan + 1] = (TempVal >> 8) & 0xff;
  692.                             DataOutThing[3 * Scan + 0] = (TempVal >> 16) & 0xff;
  693.                         }
  694.                     break;
  695.                 case eOutput32Bits:
  696.                     for (Scan = 0; Scan < Limit; Scan += 1)
  697.                         {
  698.                             largefixedsigned        TempVal;
  699.  
  700.                             PRNGCHK(Buffer,&(((largefixedsigned*)Buffer)[Scan]),
  701.                                 sizeof(((largefixedsigned*)Buffer)[Scan]));
  702.                             TempVal = ((largefixedsigned*)Buffer)[Scan];
  703.                             PRNGCHK(DataOutThing,&(DataOutThing[4 * Scan + 0]),
  704.                                 sizeof(DataOutThing[4 * Scan + 0]) * 4);
  705.                             DataOutThing[4 * Scan + 3] = TempVal & 0xff;
  706.                             DataOutThing[4 * Scan + 2] = (TempVal >> 8) & 0xff;
  707.                             DataOutThing[4 * Scan + 1] = (TempVal >> 16) & 0xff;
  708.                             DataOutThing[4 * Scan + 0] = (TempVal >> 24) & 0xff;
  709.                         }
  710.                     break;
  711.             }
  712.  
  713.         /* write data to the file */
  714.      RetryPoint:
  715.         UnwritableBytes = WriteToFile(Info->OutputFile,DataOutThing,DataOutInBytes);
  716.         if (UnwritableBytes != 0)
  717.             {
  718.                 switch (AskYesNoCancel("An error occurred writing to the file.  The disk "
  719.                     "may be full.  Do you want to try writing again?",NIL,"Retry","Abort",NIL))
  720.                     {
  721.                         default:
  722.                             EXECUTE(PRERR(ForceAbort,"SynthToAIFFFile:  bad value from AskYesNoCancel"));
  723.                             break;
  724.                         case eYes:
  725.                             /* back up */
  726.                             if (!SetFilePosition(Info->OutputFile,GetFilePosition(Info->OutputFile)
  727.                                 - (UnwritableBytes - DataOutInBytes)))
  728.                                 {
  729.                                     AlertHalt("File position could not be reset.  Aborting synthesis.",NIL);
  730.                                     return False;
  731.                                 }
  732.                             goto RetryPoint;
  733.                         case eNo:
  734.                             /* clean up */
  735.                             SetFilePosition(Info->OutputFile,GetFilePosition(Info->OutputFile)
  736.                                 - (UnwritableBytes - DataOutInBytes));
  737.                             return False;
  738.                     }
  739.             }
  740.  
  741.         Info->TotalSampleCount += NumFrames;
  742.  
  743.         UpdateSynthWindow(Info->Window,Info->SamplingRate,Info->TotalSampleCount,
  744.             Info->ClippedSampleCount,False);
  745.  
  746.         return True;
  747.     }
  748.  
  749.  
  750. /* this routine opens a file and dumps the data to it. */
  751. void                                    SynthToAIFFFile(struct MainWindowRec* MainWindow,
  752.                                                 struct ArrayRec* ListOfTracks, struct TrackObjectRec* KeyTrack,
  753.                                                 long FrameToStartAt, long SamplingRate, long EnvelopeRate,
  754.                                                 MyBoolean UseStereo, LargeBCDType DefaultBeatsPerMinute,
  755.                                                 LargeBCDType OverallVolumeScalingReciprocal,
  756.                                                 MyBoolean InterpOverTime, MyBoolean InterpAcrossWaves,
  757.                                                 LargeBCDType ScanningGap, OutputNumBitsType NumBitsOut,
  758.                                                 MyBoolean ClipWarn)
  759.     {
  760.         StateRecord                    StateInfo;
  761.         SynthErrorCodes            SynthErrorReturnCode;
  762.         FileSpec*                        WhereToSaveFile;
  763.         ErrorDaemonRec*            ErrorDaemon;
  764.  
  765.         CheckPtrExistence(MainWindow);
  766.         CheckPtrExistence(ListOfTracks);
  767.         CheckPtrExistence(KeyTrack);
  768.  
  769.         StateInfo.UseStereo = UseStereo;
  770.         StateInfo.SamplingRate = SamplingRate;
  771.         StateInfo.NumBitsOut = NumBitsOut;
  772.  
  773.         StateInfo.TotalSampleCount = 0;
  774.         StateInfo.ClippedSampleCount = 0;
  775.         StateInfo.MaxClipExtent = 0;
  776.  
  777.         StateInfo.CancelCheck = 0;
  778.  
  779.         StateInfo.Window = NewSynthWindow(EnvelopeRate / 2,True/*show clipping*/);
  780.         if (StateInfo.Window == NIL)
  781.             {
  782.                 AlertHalt("There is not enough memory available to perform synthesis.",NIL);
  783.              SetupFailurePoint1:
  784.                 return;
  785.             }
  786.  
  787.         WhereToSaveFile = PutFile("AIFF Output File");
  788.         if (WhereToSaveFile == NIL)
  789.             {
  790.              SetupFailurePoint2:
  791.                 DisposeSynthWindow(StateInfo.Window);
  792.                 goto SetupFailurePoint1;
  793.             }
  794.  
  795.         if (!CreateFile(WhereToSaveFile,ApplicationCreator,CODE4BYTES('A','I','F','F')))
  796.             {
  797.                 AlertHalt("Unable to create the file.",NIL);
  798.              SetupFailurePoint3:
  799.                 DisposeFileSpec(WhereToSaveFile);
  800.                 goto SetupFailurePoint2;
  801.             }
  802.  
  803.         if (!OpenFile(WhereToSaveFile,&(StateInfo.OutputFile),eReadAndWrite))
  804.             {
  805.                 AlertHalt("Unable to open the file for writing.",NIL);
  806.              SetupFailurePoint4:
  807.                 goto SetupFailurePoint3;
  808.             }
  809.  
  810.         if (!SetUpAIFFHeader(StateInfo.OutputFile,&StateInfo))
  811.             {
  812.                 AlertHalt("Unable to write data to the file.",NIL);
  813.              SetupFailurePoint5:
  814.                 CloseFile(StateInfo.OutputFile);
  815.                 goto SetupFailurePoint4;
  816.             }
  817.  
  818.         ErrorDaemon = NewErrorDaemon();
  819.         if (ErrorDaemon == NIL)
  820.             {
  821.                 AlertHalt("There is not enough memory available to perform synthesis.",NIL);
  822.              SetupFailurePoint6:
  823.                 goto SetupFailurePoint5;
  824.             }
  825.  
  826.         StateInfo.Buffer = AllocPtrCanFail(0,"StateInfo.Buffer");
  827.         if (StateInfo.Buffer == NIL)
  828.             {
  829.                 AlertHalt("There is not enough memory available to perform synthesis.",NIL);
  830.              SetupFailurePoint7:
  831.                 DisposeErrorDaemon(ErrorDaemon);
  832.                 goto SetupFailurePoint6;
  833.             }
  834.         StateInfo.BufferSizeInBytes = 0;
  835.  
  836.         StateInfo.DataOutThing = AllocPtrCanFail(0,"StateInfo.DataOutThing");
  837.         if (StateInfo.DataOutThing == NIL)
  838.             {
  839.                 AlertHalt("There is not enough memory available to perform synthesis.",NIL);
  840.              SetupFailurePoint8:
  841.                 ReleasePtr(StateInfo.Buffer);
  842.                 goto SetupFailurePoint7;
  843.             }
  844.         StateInfo.DataOutInBytes = 0;
  845.  
  846.         SynthErrorReturnCode = Synthesizer(MainWindow,
  847.             (MyBoolean (*)(void*,largefixedsigned*,long,MyBoolean*))&CallbackRoutine,
  848.             &StateInfo,ListOfTracks,KeyTrack,FrameToStartAt,SamplingRate,EnvelopeRate,
  849.             UseStereo,DefaultBeatsPerMinute,OverallVolumeScalingReciprocal,InterpOverTime,
  850.             InterpAcrossWaves,ScanningGap,ErrorDaemon);
  851.  
  852.         UpdateSynthWindow(StateInfo.Window,StateInfo.SamplingRate,StateInfo.TotalSampleCount,
  853.             StateInfo.ClippedSampleCount,True);
  854.  
  855.         if (!ResolveAIFFHeader(StateInfo.OutputFile,&StateInfo))
  856.             {
  857.                 AlertHalt("Unable to properly finalize the data in the file.  It will "
  858.                     "probably be unusable without manual repair.",NIL);
  859.             }
  860.  
  861.         switch (SynthErrorReturnCode)
  862.             {
  863.                 default:
  864.                     EXECUTE(PRERR(AllowResume,
  865.                         "SynthToSoundDevice:  bad return code from Synthesizer()"));
  866.                     break;
  867.                 case eSynthDone:
  868.                     break;
  869.                 case eSynthNoMemory:
  870.                     AlertHalt("There is not enough memory available to continue synthesis.",NIL);
  871.                     break;
  872.                 case eSynthUserCancelled:
  873.                     break;
  874.                 /* case eSynthProgramError: */
  875.                     break;
  876.                 case eSynthPrereqError:
  877.                     break;
  878.                 case eSynthUndefinedInstrumentError:
  879.                     break;
  880.                 case eSynthDataSubmitError:
  881.                     break;
  882.                 case eSynthDuplicateNames:
  883.                     break;
  884.             }
  885.  
  886.         CloseFile(StateInfo.OutputFile);
  887.         DisposeFileSpec(WhereToSaveFile);
  888.         DisposeSynthWindow(StateInfo.Window);
  889.         ReleasePtr(StateInfo.Buffer);
  890.         ReleasePtr(StateInfo.DataOutThing);
  891.  
  892.         if (ErrorDaemonDidClampingOccur(ErrorDaemon))
  893.             {
  894.                 ClampWarnDialog(ErrorDaemonGetMaxClamping(ErrorDaemon),
  895.                     ErrorDaemonGetMaxClamping(ErrorDaemon)
  896.                     * LargeBCD2Double(OverallVolumeScalingReciprocal));
  897.             }
  898.          else
  899.             {
  900.                 if (ClipWarn && (StateInfo.ClippedSampleCount != 0))
  901.                     {
  902.                         ClipWarnDialog(StateInfo.ClippedSampleCount,StateInfo.TotalSampleCount,
  903.                             largefixed2double(StateInfo.MaxClipExtent),
  904.                             largefixed2double(StateInfo.MaxClipExtent)
  905.                             * LargeBCD2Double(OverallVolumeScalingReciprocal),False);
  906.                     }
  907.             }
  908.  
  909.         DisposeErrorDaemon(ErrorDaemon);
  910.     }
  911.